home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus Leser 15 / Amiga Plus Leser CD 15.iso / Tools / Development / MosaicSRC / src / HTMLlists.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-03-13  |  17.0 KB  |  878 lines

  1. // MDF - PORT FROM NCSA VERSION 2.1
  2.  
  3. /****************************************************************************
  4.  * NCSA Mosaic for the X Window System                                      *
  5.  * Software Development Group                                               *
  6.  * National Center for Supercomputing Applications                          *
  7.  * University of Illinois at Urbana-Champaign                               *
  8.  * 605 E. Springfield, Champaign IL 61820                                   *
  9.  * mosaic@ncsa.uiuc.edu                                                     *
  10.  *                                                                          *
  11.  * Copyright (C) 1993, Board of Trustees of the University of Illinois      *
  12.  *                                                                          *
  13.  * NCSA Mosaic software, both binary and source (hereafter, Software) is    *
  14.  * copyrighted by The Board of Trustees of the University of Illinois       *
  15.  * (UI), and ownership remains with the UI.                                 *
  16.  *                                                                          *
  17.  * The UI grants you (hereafter, Licensee) a license to use the Software    *
  18.  * for academic, research and internal business purposes only, without a    *
  19.  * fee.  Licensee may distribute the binary and source code (if released)   *
  20.  * to third parties provided that the copyright notice and this statement   *
  21.  * appears on all copies and that no charge is associated with such         *
  22.  * copies.                                                                  *
  23.  *                                                                          *
  24.  * Licensee may make derivative works.  However, if Licensee distributes    *
  25.  * any derivative work based on or derived from the Software, then          *
  26.  * Licensee will (1) notify NCSA regarding its distribution of the          *
  27.  * derivative work, and (2) clearly notify users that such derivative       *
  28.  * work is a modified version and not the original NCSA Mosaic              *
  29.  * distributed by the UI.                                                   *
  30.  *                                                                          *
  31.  * Any Licensee wishing to make commercial use of the Software should       *
  32.  * contact the UI, c/o NCSA, to negotiate an appropriate license for such   *
  33.  * commercial use.  Commercial use includes (1) integration of all or       *
  34.  * part of the source code into a product for sale or license by or on      *
  35.  * behalf of Licensee to third parties, or (2) distribution of the binary   *
  36.  * code or source code to third parties that need it to utilize a           *
  37.  * commercial product sold or licensed by or on behalf of Licensee.         *
  38.  *                                                                          *
  39.  * UI MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR   *
  40.  * ANY PURPOSE.  IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED          *
  41.  * WARRANTY.  THE UI SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY THE    *
  42.  * USERS OF THIS SOFTWARE.                                                  *
  43.  *                                                                          *
  44.  * By using or copying this Software, Licensee agrees to abide by the       *
  45.  * copyright law and all other applicable laws of the U.S. including, but   *
  46.  * not limited to, export control laws, and the terms of this license.      *
  47.  * UI shall have the right to terminate this license immediately by         *
  48.  * written notice upon Licensee's breach of, or non-compliance with, any    *
  49.  * of its terms.  Licensee may be held legally responsible for any          *
  50.  * copyright infringement that is caused or encouraged by Licensee's        *
  51.  * failure to abide by the terms of this license.                           *
  52.  *                                                                          *
  53.  * Comments and questions are welcome and can be sent to                    *
  54.  * mosaic-x@ncsa.uiuc.edu.                                                  *
  55.  ****************************************************************************/
  56.  
  57. #ifdef _AMIGA
  58. #include <string.h>
  59. #include <stdlib.h>
  60. #include <ctype.h>
  61. #endif /* _AMIGA */
  62. #include <exec/types.h>
  63. #include <stdio.h>
  64. #include "HTML.h"
  65.  
  66. /*
  67.  * Code to manage a linked list of parsed HTML objects generated
  68.  * from a raw text file.
  69.  * Also code to manage a linked list of formatted elements that
  70.  * make up a page of a formatted document.
  71.  */
  72.  
  73.  
  74. /*
  75.  * Free up the passed linked list of parsed elements, freeing
  76.  * all memory associates with each element.
  77.  */
  78. void
  79. FreeObjList(struct mark_up *List)
  80. {
  81.     struct mark_up *current;
  82.     struct mark_up *mptr;
  83.  
  84.     current = List;
  85.     while (current != NULL)
  86.     {
  87.         mptr = current;
  88.         current = current->next;
  89.         mptr->next = NULL;
  90.         if (mptr->start != NULL)
  91.         {
  92.             free((char *)mptr->start);
  93.         }
  94.         if (mptr->text != NULL)
  95.         {
  96.             free((char *)mptr->text);
  97.         }
  98.         if (mptr->end != NULL)
  99.         {
  100.             free((char *)mptr->end);
  101.         }
  102.         free((char *)mptr);
  103.     }
  104. }
  105.  
  106.  
  107. /*
  108.  * Add an object to the parsed object list.
  109.  * return a pointer to the current (end) position in the list.
  110.  * If the object is a normal text object containing nothing but
  111.  * white space, throw it out, unless we have been told to keep
  112.  * white space.
  113.  */
  114. struct mark_up *
  115. AddObj(struct mark_up **listp, struct mark_up *current, struct mark_up *mark,
  116.        int keep_wsp)
  117. {
  118.     if (mark == NULL)
  119.     {
  120.         return(current);
  121.     }
  122.  
  123.     /*
  124.      * Throw out normal text blocks that are only white space,
  125.      * unless keep_wsp is set.
  126.      */
  127.     if ((mark->type == M_NONE)&&(!keep_wsp))
  128.     {
  129.         char *ptr;
  130.  
  131.         ptr = mark->text;
  132.         if (ptr == NULL)
  133.         {
  134.             free((char *)mark);
  135.             return(current);
  136.         }
  137.  
  138. /*
  139.  * No longer throw out whitespace, it is important to keep
  140.  * white space between tags.
  141.         while ((*ptr == ' ')||(*ptr == '\t')||(*ptr == '\n'))
  142.         {
  143.             ptr++;
  144.         }
  145.  *
  146.  */
  147.  
  148.         if (*ptr == '\0')
  149.         {
  150.             free(mark->text);
  151.             free((char *)mark);
  152.             return(current);
  153.         }
  154.     }
  155.  
  156.     /*
  157.      * Add object to either the head of the list for a new list,
  158.      * or at the end after the current pointer.
  159.      */
  160.     if (*listp == NULL)
  161.     {
  162.         *listp = mark;
  163.         current = *listp;
  164.     }
  165.     else
  166.     {
  167.         current->next = mark;
  168.         current = current->next;
  169.     }
  170.  
  171.     current->next = NULL;
  172.  
  173.     return(current);
  174. }
  175.  
  176.  
  177. #ifdef DEBUG
  178.  
  179. /*
  180.  * Convert type number to a printed string for debug
  181.  */
  182. void
  183. PrintType(int type)
  184. {
  185.     switch(type)
  186.     {
  187.         case M_NONE:
  188.             printf("M_NONE");
  189.             break;
  190.         case M_TITLE:
  191.             printf("M_TITLE");
  192.             break;
  193.         case M_FIXED:
  194.             printf("M_FIXED");
  195.             break;
  196.         case M_BOLD:
  197.             printf("M_BOLD");
  198.             break;
  199.         case M_ITALIC:
  200.             printf("M_ITALIC");
  201.             break;
  202.         case M_EMPHASIZED:
  203.             printf("M_EMPHASIZED");
  204.             break;
  205.         case M_STRONG:
  206.             printf("M_STRONG");
  207.             break;
  208.         case M_CODE:
  209.             printf("M_CODE");
  210.             break;
  211.         case M_SAMPLE:
  212.             printf("M_SAMPLE");
  213.             break;
  214.         case M_KEYBOARD:
  215.             printf("M_KEYBOARD");
  216.             break;
  217.         case M_VARIABLE:
  218.             printf("M_VARIABLE");
  219.             break;
  220.         case M_CITATION:
  221.             printf("M_CITATION");
  222.             break;
  223.         case M_STRIKEOUT:
  224.             printf("M_STRIKEOUT");
  225.             break;
  226.         case M_HEADER_1:
  227.             printf("M_HEADER_1");
  228.             break;
  229.         case M_HEADER_2:
  230.             printf("M_HEADER_2");
  231.             break;
  232.         case M_HEADER_3:
  233.             printf("M_HEADER_3");
  234.             break;
  235.         case M_HEADER_4:
  236.             printf("M_HEADER_4");
  237.             break;
  238.         case M_HEADER_5:
  239.             printf("M_HEADER_5");
  240.             break;
  241.         case M_HEADER_6:
  242.             printf("M_HEADER_6");
  243.             break;
  244.         case M_ANCHOR:
  245.             printf("M_ANCHOR");
  246.             break;
  247.         case M_PARAGRAPH:
  248.             printf("M_PARAGRAPH");
  249.             break;
  250.         case M_ADDRESS:
  251.             printf("M_ADDRESS");
  252.             break;
  253.         case M_PLAIN_TEXT:
  254.             printf("M_PLAIN_TEXT");
  255.             break;
  256.         case M_LISTING_TEXT:
  257.             printf("M_LISTING_TEXT");
  258.             break;
  259.         case M_UNUM_LIST:
  260.             printf("M_UNUM_LIST");
  261.             break;
  262.         case M_NUM_LIST:
  263.             printf("M_NUM_LIST");
  264.             break;
  265.         case M_MENU:
  266.             printf("M_MENU");
  267.             break;
  268.         case M_DIRECTORY:
  269.             printf("M_DIRECTORY");
  270.             break;
  271.         case M_LIST_ITEM:
  272.             printf("M_LIST_ITEM");
  273.             break;
  274.         case M_DESC_LIST:
  275.             printf("M_DESC_LIST");
  276.             break;
  277.         case M_DESC_TITLE:
  278.             printf("M_DESC_TITLE");
  279.             break;
  280.         case M_DESC_TEXT:
  281.             printf("M_DESC_TEXT");
  282.             break;
  283.         case M_IMAGE:
  284.             printf("M_IMAGE");
  285.             break;
  286.         case M_SELECT:
  287.             printf("M_SELECT");
  288.             break;
  289.         case M_OPTION:
  290.             printf("M_OPTION");
  291.             break;
  292.         case M_INPUT:
  293.             printf("M_INPUT");
  294.             break;
  295.         case M_TEXTAREA:
  296.             printf("M_TEXTAREA");
  297.             break;
  298.         case M_FORM:
  299.             printf("M_FORM");
  300.             break;
  301.         case M_INDEX:
  302.             printf("M_INDEX");
  303.             break;
  304.         case M_HRULE:
  305.             printf("M_HRULE");
  306.             break;
  307.         case M_BASE:
  308.             printf("M_BASE");
  309.             break;
  310.         case M_LINEBREAK:
  311.             printf("M_LINEBREAK");
  312.             break;
  313.         case M_BLOCKQUOTE:
  314.             printf("M_BLOCKQUOTE");
  315.             break;
  316.         default:
  317.             printf("UNKNOWN %d", type);
  318.             break;
  319.     }
  320. }
  321.  
  322.  
  323. /*
  324.  * Print the contents of a parsed object list, for debug
  325.  */
  326. void
  327. PrintList(struct mark_up *list)
  328. {
  329.     struct mark_up *mptr;
  330.  
  331.     mptr = list;
  332.     while (mptr != NULL)
  333.     {
  334.         PrintType(mptr->type);
  335.         if (mptr->is_end)
  336.         {
  337.             printf(" END");
  338.         }
  339.         else
  340.         {
  341.             printf(" START");
  342.         }
  343.         if (mptr->text != NULL)
  344.         {
  345.             printf("\n{\n\t");
  346.             printf("%s", mptr->text);
  347.             printf("}\n");
  348.         }
  349.         else
  350.         {
  351.             printf("\n");
  352.         }
  353.         mptr = mptr->next;
  354.     }
  355. }
  356.  
  357. #endif /* DEBUG */
  358.  
  359.  
  360. /*
  361.  * Used to find the longest line (in characters) in a collection
  362.  * of text blocks.  cnt is the running count of characters, and
  363.  * txt is the pointer to the current text block.  Since we are
  364.  * finding line widths, a newline resets the width count.
  365.  */
  366. char *
  367. MaxTextWidth(char *txt, int *cnt)
  368. {
  369.     char *start;
  370.     char *end;
  371.     int width;
  372.  
  373.     if (txt == NULL)
  374.     {
  375.         return(NULL);
  376.     }
  377.  
  378.     width = *cnt;
  379.     start = txt;
  380.  
  381.     /*
  382.      * If this blocks starts with a newline, reset the width
  383.      * count, and skip the newline.
  384.      */
  385.     if (*start == '\n')
  386.     {
  387.         width = 0;
  388.         start++;
  389.     }
  390.  
  391.     end = start;
  392.  
  393.     /*
  394.      * count characters, stoping either at a newline, or at the
  395.      * end of this text block.  Expand tabs.
  396.      */
  397.     while ((*end != '\0')&&(*end != '\n'))
  398.     {
  399.         if (*end == '\t')
  400.         {
  401.             width = ((width / 8) + 1) * 8;
  402.         }
  403.         else
  404.         {
  405.             width++;
  406.         }
  407.         end++;
  408.     }
  409.  
  410.     *cnt = width;
  411.     return(end);
  412. }
  413.  
  414.  
  415. /*
  416.  * Free up the passed linked list of formatted elements, freeing
  417.  * all memory associates with each element.
  418.  */
  419. void
  420. FreeLineList(struct ele_rec *list)
  421. {
  422.     struct ele_rec *current;
  423.     struct ele_rec *eptr;
  424.  
  425.     current = list;
  426.     while (current != NULL)
  427.     {
  428.         eptr = current;
  429.         current = current->next;
  430.         eptr->next = NULL;
  431.         if (eptr->edata != NULL)
  432.         {
  433.             free((char *)eptr->edata);
  434.         }
  435.         if (eptr->anchorHRef != NULL)
  436.         {
  437.             free((char *)eptr->anchorHRef);
  438.         }
  439.         if (eptr->anchorName != NULL)
  440.         {
  441.             free((char *)eptr->anchorName);
  442.         }
  443.         free((char *)eptr);
  444.     }
  445. }
  446.  
  447.  
  448. /*
  449.  * Add an element to the linked list of formatted elements.
  450.  * return a pointer to the current (end) position in the list.
  451.  */
  452. struct ele_rec *
  453. AddEle(struct ele_rec **elistp, struct ele_rec *current, struct ele_rec *eptr)
  454. {
  455.     if (eptr == NULL)
  456.     {
  457.         return(current);
  458.     }
  459.  
  460.     /*
  461.      * Add object to either the head of the list for a new list,
  462.      * or at the end after the current pointer.
  463.      */
  464.     if (*elistp == NULL)
  465.     {
  466.         *elistp = eptr;
  467.         (*elistp)->next = NULL;
  468.         (*elistp)->prev = NULL;
  469.         current = *elistp;
  470.     }
  471.     else
  472.     {
  473.         current->next = eptr;
  474.         eptr->prev = current;
  475.         current = current->next;
  476.         current->next = NULL;
  477.     }
  478.     return(current);
  479. }
  480.  
  481.  
  482. /*
  483.  * Contruct and return an array of pointers into the element list that
  484.  * indexes the elements by line number.
  485.  * Note, lines containing only while space will have NULL pointers
  486.  * into the element list.
  487.  */
  488. struct ele_rec **
  489. MakeLineList(struct ele_rec *elist, int max_line)
  490. {
  491.     int i;
  492.     struct ele_rec *eptr;
  493.     struct ele_rec **ll;
  494.  
  495.     /*
  496.      * malloc index array
  497.      */
  498.     ll = (struct ele_rec **)malloc(sizeof(struct ele_rec *) * max_line);
  499.     if (ll == NULL)
  500.     {
  501.         fprintf(stderr, "cannot allocate space for line list\n");
  502.         exit(1);
  503.     }
  504.  
  505.     /*
  506.      * zero the index array
  507.      */
  508.     for (i=0; i<max_line; i++)
  509.     {
  510.         ll[i] = NULL;
  511.     }
  512.  
  513.     /*
  514.      * fill in pointers to beginning of the lines
  515.      */
  516.     eptr = elist;
  517.     while (eptr != NULL)
  518.     {
  519.         if (eptr->line_number > max_line)
  520.         {
  521.             break;
  522.         }
  523.  
  524.         if (ll[eptr->line_number - 1] == NULL)
  525.         {
  526.             ll[eptr->line_number - 1] = eptr;
  527.         }
  528.  
  529.         eptr = eptr->next;
  530.     }
  531.     return(ll);
  532. }
  533.  
  534.  
  535. /*
  536.  * Passed in 2 element pointers, and element positions.
  537.  * Function should return 1 if if start occurs before end.
  538.  * Otherwise return 0.
  539.  */
  540. int
  541. ElementLessThan(struct ele_rec *start, struct ele_rec *end, int start_pos,
  542.         int end_pos)
  543. {
  544.     struct ele_rec *current;
  545.  
  546.     /*
  547.      * Deal with start or end being NULL
  548.      */
  549.     if ((start == NULL)&&(end == NULL))
  550.     {
  551.         return(0);
  552.     }
  553.     else if ((start == NULL)&&(end != NULL))
  554.     {
  555.         return(1);
  556.     }
  557.     else if ((start != NULL)&&(end == NULL))
  558.     {
  559.         return(0);
  560.     }
  561.  
  562.     /*
  563.      * Deal with easy identical case
  564.      */
  565.     if (start == end)
  566.     {
  567.         if (start_pos < end_pos)
  568.         {
  569.             return(1);
  570.         }
  571.         else
  572.         {
  573.             return(0);
  574.         }
  575.     }
  576.  
  577.     /*
  578.      * We know element Ids are always equal or increasing within a
  579.      * list.
  580.      */
  581.     if (start->ele_id < end->ele_id)
  582.     {
  583.         return(1);
  584.     }
  585.     else if (start->ele_id == end->ele_id)
  586.     {
  587.         current = start;
  588.         while (current != NULL)
  589.         {
  590.             if (current->ele_id != start->ele_id)
  591.             {
  592.                 break;
  593.             }
  594.             else if (current == end)
  595.             {
  596.                 break;
  597.             }
  598.             current = current->next;
  599.         }
  600.         if (current == end)
  601.         {
  602.             return(1);
  603.         }
  604.         else
  605.         {
  606.             return(0);
  607.         }
  608.     }
  609.     else
  610.     {
  611.         return(0);
  612.     }
  613. }
  614.  
  615.  
  616. /*
  617.  * Passed in 2 element pointers, and element positions.
  618.  * Function should return 1 if they need to be swapped in order for then
  619.  * to proceed left to right and top to bottom in the text.
  620.  * Otherwise return 0.
  621.  */
  622. int
  623. SwapElements(struct ele_rec *start, struct ele_rec *end, int start_pos,
  624.          int end_pos)
  625. {
  626.     struct ele_rec *current;
  627.  
  628.     /*
  629.      * Deal with start or end being NULL
  630.      */
  631.     if ((start == NULL)&&(end == NULL))
  632.     {
  633.         return(0);
  634.     }
  635.     else if ((start == NULL)&&(end != NULL))
  636.     {
  637.         return(1);
  638.     }
  639.     else if ((start != NULL)&&(end == NULL))
  640.     {
  641.         return(0);
  642.     }
  643.  
  644.     /*
  645.      * Deal with easy identical case
  646.      */
  647.     if (start == end)
  648.     {
  649.         if (start_pos > end_pos)
  650.         {
  651.             return(1);
  652.         }
  653.         else
  654.         {
  655.             return(0);
  656.         }
  657.     }
  658.  
  659.     /*
  660.      * We know element Ids are always equal or increasing within a
  661.      * list.
  662.      */
  663.     if (start->ele_id < end->ele_id)
  664.     {
  665.         return(0);
  666.     }
  667.     else if (start->ele_id == end->ele_id)
  668.     {
  669.         current = start;
  670.         while (current != NULL)
  671.         {
  672.             if (current->ele_id != start->ele_id)
  673.             {
  674.                 break;
  675.             }
  676.             else if (current == end)
  677.             {
  678.                 break;
  679.             }
  680.             current = current->next;
  681.         }
  682.         if (current == end)
  683.         {
  684.             return(0);
  685.         }
  686.         else
  687.         {
  688.             return(1);
  689.         }
  690.     }
  691.     else
  692.     {
  693.         return(1);
  694.     }
  695. }
  696.  
  697.  
  698. /*
  699.  * Free up the allocated list of internal hrefs.
  700.  */
  701. void
  702. FreeHRefs(struct ref_rec *list)
  703. {
  704.     struct ref_rec *hptr;
  705.     struct ref_rec *tptr;
  706.  
  707.     hptr = list;
  708.     while (hptr != NULL)
  709.     {
  710.         tptr = hptr;
  711.         hptr = hptr->next;
  712.         if (tptr->anchorHRef != NULL)
  713.         {
  714.             free((char *)tptr->anchorHRef);
  715.         }
  716.         free((char *)tptr);
  717.     }
  718. }
  719.  
  720.  
  721. /*
  722.  * Find an element in the linked list of Internal HREFS.
  723.  * return a pointer to the element, or NULL if not found.
  724.  */
  725. struct ref_rec *
  726. FindHRef(struct ref_rec *list, char *href)
  727. {
  728.     struct ref_rec *hptr;
  729.  
  730.     if (href == NULL)
  731.     {
  732.         return(NULL);
  733.     }
  734.  
  735.     hptr = list;
  736.     while (hptr != NULL)
  737.     {
  738.         if (strcmp(hptr->anchorHRef, href) == 0)
  739.         {
  740.             break;
  741.         }
  742.         hptr = hptr->next;
  743.     }
  744.     return(hptr);
  745. }
  746.  
  747.  
  748. /*
  749.  * Add an element to the linked list of Internal HREFS we
  750.  * have visited before.
  751.  * return a pointer to the head of the new list.
  752.  */
  753. struct ref_rec *
  754. AddHRef(struct ref_rec *list, char *href)
  755. {
  756.     struct ref_rec *hptr;
  757.  
  758.     if (href == NULL)
  759.     {
  760.         return(list);
  761.     }
  762.  
  763.     hptr = FindHRef(list, href);
  764.  
  765.     if (hptr == NULL)
  766.     {
  767.         hptr = (struct ref_rec *)malloc(sizeof(struct ref_rec));
  768.         if (hptr == NULL)
  769.         {
  770.             fprintf(stderr, "cannot extend internal href list\n");
  771.             return(list);
  772.         }
  773.         hptr->anchorHRef = (char *)malloc(strlen(href) + 1);
  774.         if (hptr->anchorHRef == NULL)
  775.         {
  776.             free((char *)hptr);
  777.             fprintf(stderr, "cannot extend internal href list\n");
  778.             return(list);
  779.         }
  780.         strcpy(hptr->anchorHRef, href);
  781.         hptr->next = list;
  782.         list = hptr;
  783.     }
  784.  
  785.     return(list);
  786. }
  787.  
  788.  
  789. /*
  790.  * Free up the allocated list of visited delayed images
  791.  */
  792. void
  793. FreeDelayedImages(struct delay_rec *list)
  794. {
  795.     struct delay_rec *iptr;
  796.     struct delay_rec *tptr;
  797.  
  798.     iptr = list;
  799.     while (iptr != NULL)
  800.     {
  801.         tptr = iptr;
  802.         iptr = iptr->next;
  803.         if (tptr->src != NULL)
  804.         {
  805.             free((char *)tptr->src);
  806.         }
  807.         free((char *)tptr);
  808.     }
  809. }
  810.  
  811.  
  812. /*
  813.  * Find an element in the linked list of visited delayed images.
  814.  * return a pointer to the element, or NULL if not found.
  815.  */
  816. struct delay_rec *
  817. FindDelayedImage(struct delay_rec *list, char *src)
  818. {
  819.     struct delay_rec *iptr;
  820.  
  821.     if (src == NULL)
  822.     {
  823.         return(NULL);
  824.     }
  825.  
  826.     iptr = list;
  827.     while (iptr != NULL)
  828.     {
  829.         if (strcmp(iptr->src, src) == 0)
  830.         {
  831.             break;
  832.         }
  833.         iptr = iptr->next;
  834.     }
  835.     return(iptr);
  836. }
  837.  
  838.  
  839. /*
  840.  * Add an element to the linked list of visited delayed images.
  841.  * return a pointer to the head of the new list.
  842.  */
  843. struct delay_rec *
  844. AddDelayedImage(struct delay_rec *list, char *src)
  845. {
  846.     struct delay_rec *iptr;
  847.  
  848.     if (src == NULL)
  849.     {
  850.         return(list);
  851.     }
  852.  
  853.     iptr = FindDelayedImage(list, src);
  854.  
  855.     if (iptr == NULL)
  856.     {
  857.         iptr = (struct delay_rec *)malloc(sizeof(struct delay_rec));
  858.         if (iptr == NULL)
  859.         {
  860.             fprintf(stderr, "cannot extend visited delayed images list\n");
  861.             return(list);
  862.         }
  863.         iptr->src = (char *)malloc(strlen(src) + 1);
  864.         if (iptr->src == NULL)
  865.         {
  866.             free((char *)iptr);
  867.             fprintf(stderr, "cannot extend visited delayed images list\n");
  868.             return(list);
  869.         }
  870.         strcpy(iptr->src, src);
  871.         iptr->next = list;
  872.         list = iptr;
  873.     }
  874.  
  875.     return(list);
  876. }
  877.  
  878.